package ift605.EquationWithTrainingAgents.behavior.common;

import java.io.IOException;
import java.io.Serializable;
import java.util.List;

import jade.core.AID;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import ift605.EquationWithAgent.server.EquationMessage;
import ift605.EquationWithTrainingAgents.agent.PoolAgent;
import ift605.EquationWithTrainingAgents.agent.TrainingAgentClient;
import ift605.EquationWithTrainingAgents.struct.DerivationInfo;
import ift605.EquationWithTrainingAgents.struct.DerivationStep;
import ift605.EquationWithTrainingAgents.struct.LearningMessage;
import ift605.EquationWithTrainingAgents.struct.PendingRequest;


public abstract class ReceiveDerivativeBehavior extends CyclicBehaviour {
	private static final long serialVersionUID = 1L;
	private MessageTemplate mTemplate = /*MessageTemplate.and(
			MessageTemplate.MatchPerformative(ACLMessage.INFORM), 
			MessageTemplate.MatchConversationId(EquationMessage.RESULT_ID));*/ MessageTemplate.MatchConversationId(EquationMessage.RESULT_ID);
	
	public abstract boolean applyDerivative(EquationMessage aEquationMessage, DerivationInfo aDerivationInfo);
	
	@Override
	public void action() {
		ACLMessage request = myAgent.receive(mTemplate);
		
		if(request != null){
			if(((PoolAgent) myAgent).isValidPerformative(request.getPerformative())){
				try{
					Serializable content = request.getContentObject();
				 
					if(content != null && content instanceof EquationMessage){
						EquationMessage eqMess = (EquationMessage)content;
						
						PoolAgent casted = ((PoolAgent)myAgent);
						
						DerivationInfo deriveInfo = casted.mInProgess.get(String.valueOf(eqMess.getRequestNumber()));
						
						if(deriveInfo == null)
						{
							System.out.println("There is a HIC with :: " + eqMess.getRequestNumber() + " COMING FROM " + request.getSender().getLocalName());
							for(String key : casted.mInProgess.keySet())
							{
								System.out.println("Possible key :: " + key);
							}
						}
						
						List<PendingRequest> pendings = casted.mEquationChunk.get(deriveInfo.Mess.requestID);
						
						for(PendingRequest req : pendings)
						{
							if(req.id == eqMess.getRequestNumber())
							{
								req.ended = true;
								req.derived = eqMess.getEquation();
								break;
							}
						}
						
						if(applyDerivative(eqMess, deriveInfo))
						{
							
							if(deriveInfo.Mess.tryDerive)
							{
								// Add his agent AID to the list of each step of derivation
								deriveInfo.Mess.derivationSteps.add(new DerivationStep(myAgent.getAID(), deriveInfo.Variation));
								deriveInfo.Mess.currentStep = deriveInfo.Mess.derivationSteps.size();
								
								// Ask to papa to verify the derived
								ACLMessage response = new ACLMessage(deriveInfo.Mess.requestID);
								response.addReceiver(new AID("Papa", AID.ISLOCALNAME));
								response.setConversationId(LearningMessage.VERIFY);
								response.setContentObject(deriveInfo.Mess);
								myAgent.send(response);
							}
							else // we just resolve the equation
							{
								deriveInfo.Mess.currentStep++;
								
								if(deriveInfo.Mess.currentStep < deriveInfo.Mess.derivationSteps.size())
								{
									// send it to next step
									ACLMessage response = new ACLMessage(deriveInfo.Mess.requestID);
									response.addReceiver(deriveInfo.Mess.derivationSteps.get(deriveInfo.Mess.currentStep).getAgent());
									response.setConversationId(LearningMessage.DERIVE);
									response.setContentObject(deriveInfo.Mess);
									myAgent.send(response);
								}
								else
								{
									// Send to LearningDerivativeAgent
									ACLMessage response = new ACLMessage(deriveInfo.Mess.requestID);
									response.addReceiver(new AID(TrainingAgentClient.NEW_AID_NAME_DERIVATIVE, AID.ISLOCALNAME));
									response.setConversationId(LearningMessage.FINAL_ANSWER);
									response.setContentObject(deriveInfo.Mess);
									myAgent.send(response);
								}
							}
						}
					}
				}
				catch (UnreadableException e) { 
					e.printStackTrace(); 
				} 
				catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		else
		{
			block();
		}
	}
}